from django.db.models import Q
from django.shortcuts import render

# Create your views here.
from random import sample
from rest_framework.decorators import action
from rest_framework.mixins import CreateModelMixin, UpdateModelMixin, ListModelMixin, RetrieveModelMixin
from rest_framework.response import Response
from rest_framework.viewsets import GenericViewSet, ModelViewSet
from rest_framework.permissions import IsAuthenticated
from rest_framework.pagination import LimitOffsetPagination, PageNumberPagination
from rest_framework.status import HTTP_404_NOT_FOUND

from users.utils import wrap_permission, MyPermission
from work.models import Label, Topic
from work.serializers import LabelSerializer, TopicSerializer, LabelTopicSerializer

from elasticsearch import Elasticsearch
import elasticsearch
from config.esConfig import HOST, PORT

es = Elasticsearch([{'host': HOST, 'port': PORT}], timeout=3600)

'''
判断当前视图类是否需要继承那些？
1、是否需要返回json格式的数据  需要:drf结构的视图类 不需要:直接使用Django
2、是否需要使用序列化器和查询集 需要:GenericViewSet 不需要:ViewSet
3、需要那些功能 增加:CreateModelMixin 修改:UpdateModelMixin 如果5个功能都需要:直接继承ModelViewSet
'''


class LabelViewSet(CreateModelMixin, UpdateModelMixin, ListModelMixin, GenericViewSet, RetrieveModelMixin):
    permission_classes = [IsAuthenticated]
    queryset = Label.objects.all()
    serializer_class = LabelSerializer

    @wrap_permission(MyPermission)
    def create(self, request, *args, **kwargs):
        request.POST._mutable = True  # 讲post请求携带的参数设置为可修改
        request.data['user'] = str(request.user.id)
        return CreateModelMixin.create(self, request, *args, **kwargs)

    def update(self, request, *args, **kwargs):
        if not Label.objects.filter(id=kwargs['pk'], user=request.user):
            return Response({'detail': '您没有权限进行修改'})
        return UpdateModelMixin.update(self, request, *args, **kwargs)

    @action(methods=['get'], detail=True)
    def examination(self, request, pk):
        try:
            label = Label.objects.get(id=pk)
        except Label.DoesNotExist:
            return Response(status=HTTP_404_NOT_FOUND)

        serializer = LabelTopicSerializer(label)
        return Response(serializer.data)


class TopicPaginationPageNumber(PageNumberPagination):
    page_size = 5
    page_size_query_param = 'size'  # 每页展示数据量
    # page_query_param = 'page'  # 多少页
    max_page_size = 100


class TopicViewSet(ModelViewSet):
    permission_classes = [MyPermission]
    queryset = Topic.objects.filter(is_delete=False)
    serializer_class = TopicSerializer

    pagination_class = TopicPaginationPageNumber

    def create(self, request, *args, **kwargs):
        request.POST._mutable = True  # 讲post请求携带的参数设置为可修改
        request.data['user'] = str(request.user.id)

        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        serializer.save()
        re_data = serializer.data
        es.index(index='topic', id=re_data['id'], body=re_data)

        return Response(re_data)

    def update(self, request, *args, **kwargs):
        if not Topic.objects.filter(id=kwargs['pk'], user=request.user):
            return Response({'detail': '您没有权限进行修改'})

        request.POST._mutable = True
        request.data['user'] = str(request.user.id)

        # 查询题目
        try:
            topic = Topic.objects.get(id=kwargs['pk'])
        except Topic.DoesNotExist:
            return Response(status=HTTP_404_NOT_FOUND)

        serializer = self.get_serializer(topic, data=request.data)
        serializer.is_valid(raise_exception=True)
        serializer.save()
        re_data = serializer.data
        es.update(index='topic', id=re_data['id'], body={'doc': re_data})

        return Response(re_data)

    def destroy(self, request, *args, **kwargs):
        if not Topic.objects.filter(id=kwargs['pk'], user=request.user):
            return Response({'detail': '您没有权限进行删除'})
        re_data = ModelViewSet.destroy(self, request, *args, **kwargs)
        es.delete(index='topic', id=kwargs['pk'])
        return re_data

    # @action(methods=['get'], detail=False)
    # def search(self, request):
    #     serializer = self.get_serializer(self.get_queryset(), many=True)
    #     data = serializer.data
    #     for i in data:
    #         es.index(index='topic', id=i['id'], body=i)
    #     return Response(serializer.data)

    # 题目高亮搜索
    @action(methods=['get'], detail=False)
    def search(self, request):
        # 获取数据进行初始化
        data = dict(request.query_params)
        page = int(data.get('page')[0]) if data.get('page') else 1
        size = int(data.get('size')[0]) if data.get('size') else 5
        subject = data.get('subject')[0] if data.get('subject') else ''

        # es搜索
        query = {
            "query": {

            },
            "highlight": {
                "pre_tags": "<span style='color:red'>",
                "post_tags": "</span>",
                "fields": {
                    "subject": {}
                }
            },
            "from": (page - 1) * size,
            "size": size,
        }
        if not subject:
            query['query'] = {"match_all": {}}
        else:
            query['query'] = {"match": {
                'subject': subject
            }}

        try:
            es_res = es.search(index='topic', body=query)

            def highlight(x):
                if x.get('highlight'):
                    x['_source']['subject'] = x['highlight']['subject'][0]
                return x['_source']

            count = es_res['hits']['total']['value']
            subject_url = f'subject={subject}' if subject else ''
            next = f'http://127.0.0.1:8000/works/topic/search/?{subject_url}&page={page + 1}&size={size}' if page * size < count else None
            previous = f'http://127.0.0.1:8000/works/topic/search/?{subject_url}&page={page - 1}&size={size}' if page > 1 else None
            results = [highlight(i) for i in es_res['hits']['hits']]
            res = {
                "count": count,
                "next": next,
                "previous": previous,
                "results": results
            }
        except elasticsearch.exceptions.NotFoundError:
            res = {
                "count": 0,
                "next": None,
                "previous": None,
                "results": []
            }

        return Response(res)


class TopicPagination(LimitOffsetPagination):
    default_limit = 5  # 指定默认查询的多少条数据
    # limit_query_param = 'limit'  # URL中指定查询多少条数据
    # offset_query_param = 'offset'  # URL中指定从第几条数据开始查询
    max_limit = 20


class TopicStudentViewSet(GenericViewSet, ListModelMixin):
    permission_classes = [IsAuthenticated]
    serializer_class = TopicSerializer
    queryset = Topic.objects.exclude(Q(is_delete=True) | Q(label__name__contains='试卷'))
    pagination_class = TopicPagination

    @action(methods=['get'], detail=False)
    def random(self, request):
        size = request.data.get('size')
        size = size if size else 3
        serializer = self.get_serializer(self.get_queryset(), many=True)
        data = sample(serializer.data, size)
        for i in data:
            i.pop('answer')
        return Response(data)

    @action(methods=['get'], detail=False)
    def search(self, request):
        # 获取数据进行初始化
        data = dict(request.query_params)
        offset = int(data.get('offset')[0]) if data.get('offset') else 0
        limit = int(data.get('limit')[0]) if data.get('limit') else 5
        subject = data.get('subject')[0] if data.get('subject') else ''

        # es搜索
        query = {
            "query": {
                "bool": {
                    "should": [

                    ],
                    "must_not": [
                        {
                            "match": {
                                "label_name": "试卷"
                            }
                        }
                    ]
                }
            },
            "highlight": {
                "pre_tags": "<span style='color:red'>",
                "post_tags": "</span>",
                "fields": {
                    "subject": {}
                }
            },
            "from": offset,
            "size": limit,
            "_source": {
                "excludes": ['answer']
            }
        }

        if not subject:
            query['query']['bool']['should'].append({"match_all": {}})
        else:
            query['query']['bool']['should'].append({"match":{
                'subject': subject
            }})

        try:
            es_res = es.search(index='topic', body=query)

            def highlight(x):
                if x.get('highlight'):
                    x['_source']['subject'] = x['highlight']['subject'][0]
                return x['_source']

            count = es_res['hits']['total']['value']
            subject_url = f'subject={subject}' if subject else ''
            next = f'http://127.0.0.1:8000/works/topic/search/?{subject_url}&offset={offset+limit}&limit={limit}' if offset+limit < count else None
            previous = f'http://127.0.0.1:8000/works/topic/search/?{subject_url}&offset={offset-limit}&limit={limit}' if offset > 1 else None
            results = [highlight(i) for i in es_res['hits']['hits']]
            res = {
                "count": count,
                "next": next,
                "previous": previous,
                "results": results
            }
        except elasticsearch.exceptions.NotFoundError:
            res = {
                "count": 0,
                "next": None,
                "previous": None,
                "results": []
            }

        return Response(res)

